package com.example.bbs.config;

import com.alibaba.fastjson.JSON;
import com.example.bbs.domain.entity.User;
import com.example.bbs.domain.model.ResponseResult;
import com.example.bbs.service.UserService;
import com.example.bbs.util.ConstantUtil;
import com.example.bbs.util.HostHold;
import com.example.bbs.util.JwtTokenUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * 授权和权限管理
 */

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserService userService;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Value("${jwt.tokenHeader}")
    private String tokenHeader;

    @Value("${jwt.tokenHead}")
    private String tokenHead;

    @Value("${jwt.expiration}")
    private int expiration;

    @Value("${server.servlet.context-path}")
    private String contextPath;

    @Override
    public void configure(WebSecurity web) {
        web.ignoring().antMatchers("/resources/**");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        http.logout().logoutUrl("/sadsad");
        http.authorizeRequests()
                .antMatchers(
                        "/doLike**",
                        "unDoLike**",
                        "/post/reply",
                        "/exit",
                        "/notice/**",
                        "/post/doPublish"
                ).hasAnyAuthority(
                ConstantUtil.AUTHORITY_TYPE_ADMIN,
                ConstantUtil.AUTHORITY_TYPE_NORMAL
        ).antMatchers(
                "/post/setTop",
                "/post/setWonderful"
        ).hasAnyAuthority(
                ConstantUtil.AUTHORITY_TYPE_ADMIN
        )
                .anyRequest().permitAll()
                .and().csrf().disable();


        http.addFilterBefore(new OncePerRequestFilter() {
            @Override
            protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
                String token = null;
                Cookie[] cookies = request.getCookies();
                if (cookies != null) {
                    for (Cookie cookie : cookies) {
                        if (cookie.getName().equals(tokenHeader)) {
                            token = cookie.getValue();
                            break;
                        }
                    }
                }

                if (!StringUtils.isBlank(token) && token.startsWith(tokenHead)) {
                    String jwt = token.substring(tokenHead.length() + 1);
                    String userId = jwtTokenUtil.getUserId(jwt);

                    User user = userService.getUserByUserId(userId);

                    if (jwtTokenUtil.isValid(jwt, user)) {
                        HostHold.set(user);
                        Authentication authentication = new UsernamePasswordAuthenticationToken(user, null,
                                userService.getAuthority(userId));
                        SecurityContextHolder.getContext().setAuthentication(authentication);

                        //是否需要刷新token
                        String newToken = jwtTokenUtil.refreshToken(jwt);
                        if (newToken != null) {
                            Cookie cookie = new Cookie(tokenHeader, newToken);
                            cookie.setPath(contextPath);
                            cookie.setMaxAge(expiration);
                            response.addCookie(cookie);
                        }
                    }

                }
                filterChain.doFilter(request, response);
            }
        }, UsernamePasswordAuthenticationFilter.class);


        http.exceptionHandling().authenticationEntryPoint(new AuthenticationEntryPoint() {
            @Override //没有权限情况下的处理
            public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
                String header = httpServletRequest.getHeader("x-requested-with");
                if (header == null) {
//                    httpServletResponse.sendRedirect(httpServletRequest.getContextPath() + "/login");
                } else {
                    httpServletResponse.setContentType("application/json;charset=utf-8");
                    PrintWriter writer = httpServletResponse.getWriter();
                    writer.write(JSON.toJSONString(ResponseResult.failure("请先登录！")));
                }
            }
        }).accessDeniedHandler(new AccessDeniedHandler() {
            @Override //权限不足情况下的处理
            public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException {
                String header = httpServletRequest.getHeader("x-requested-with");
                if (header == null) {
//                    httpServletResponse.sendRedirect(httpServletRequest.getContextPath() + "/denied");
                } else {
                    httpServletResponse.setContentType("application/json;charset=utf-8");
                    PrintWriter writer = httpServletResponse.getWriter();
                    writer.write(JSON.toJSONString(ResponseResult.failure("没有权限！")));
                }
            }
        });

    }

}
